/*
 * Copyright (C) 2000 - 2024 Silverpeas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * As a special exception to the terms and conditions of version 3.0 of
 * the GPL, you may redistribute this Program in connection with Free/Libre
 * Open Source Software ("FLOSS") applications as described in Silverpeas's
 * FLOSS exception.  You should have received a copy of the text describing
 * the FLOSS exception, and it is also available here:
 * "https://www.silverpeas.org/legal/floss_exception.html"
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
package org.silverpeas.core.web.authentication.credentials;

import org.silverpeas.core.admin.service.AdminException;
import org.silverpeas.core.annotation.Service;
import org.silverpeas.core.cache.service.CacheAccessorProvider;
import org.silverpeas.core.security.authentication.AuthenticationResponse;
import org.silverpeas.core.security.authentication.verifier.AuthenticationUserVerifierFactory;
import org.silverpeas.core.security.authentication.verifier.UserMustAcceptTermsOfServiceVerifier;
import org.silverpeas.kernel.util.StringUtil;
import org.silverpeas.kernel.logging.SilverLogger;
import org.silverpeas.core.web.http.HttpRequest;

import javax.servlet.http.HttpServletRequest;

/**
 * Navigation case : user accepts terms of service.
 */
@Service
public class TermsOfServiceResponseHandler extends CredentialsFunctionHandler {

  @Override
  public String getFunction() {
    return "TermsOfServiceResponse";
  }

  @Override
  public String doAction(HttpServletRequest request) {
    HttpRequest httpRequest = (HttpRequest) request;

    // Retrieving the terms of service token.
    String tosToken = httpRequest.getParameter("tosToken");

    // If it doesn't exist, it is a technical error or a suspicious http request
    if (StringUtil.isDefined(tosToken)) {

      // Retrieving the verifier behind the token
      UserMustAcceptTermsOfServiceVerifier verifier = AuthenticationUserVerifierFactory.
          getUserMustAcceptTermsOfServiceVerifier(tosToken);

      // If it doesn't exists :
      // - too much time before refusing or accepting
      // - suspicious HTTP REQUEST (someone tries to connect several times with the same tosToken
      // for example)
      if (verifier.getUser() == null) {
        return getErrorDestination(UserMustAcceptTermsOfServiceVerifier.ERROR_USER_TOS_TIMEOUT);
      }

      try {

        // Retrieving the user choice : refusing or accepting
        boolean tosAccepted = httpRequest.getParameterAsBoolean("tosAccepted");

        // If the user refused, it is redirected to the login page
        if (!tosAccepted) {
          return getErrorDestination(UserMustAcceptTermsOfServiceVerifier.ERROR_USER_TOS_REFUSED);
        }

        // Indicating the user accepts terms of service
        try {
          getAdminService().userAcceptsTermsOfService(verifier.getUser().getId());
        } catch (AdminException e) {
          SilverLogger.getLogger(this).error("terms of service error with login {0}",
              new String[]{verifier.getUser().getLogin()}, e);
          return getErrorDestination(AuthenticationResponse.Status.UNKNOWN_FAILURE.getCode());
        }

        // Using internalAuthToken request attribute that uses common cache services in order to
        // authenticate a user by mapping a user to a token.
        // The token is generated by the Cache.
        // This below instruction is to handle the case that user must accept terms of service at
        request.setAttribute("internalAuthToken",
            CacheAccessorProvider.getApplicationCacheAccessor().getCache().add(verifier.getUser()));
        // each logon
        request.setAttribute("skipTermsOfServiceAcceptance", true);
        return "/AuthenticationServlet";

      } finally {

        // Clearing the verifier from the memory (AVOID HTTP REQUEST REPLAY).
        verifier.clearCache();
      }
    }
    return getErrorDestination(AuthenticationResponse.Status.UNKNOWN_FAILURE.getCode());
  }

  /**
   * The error destination is always the login page.
   *
   * @param errorCode the error code.
   * @return the relative web page to go when an error occurs.
   */
  private String getErrorDestination(String errorCode) {
    return "/Login?ErrorCode=" + errorCode;
  }
}
